<?php
/**
 * Created by PhpStorm.
 * User: 牛赞赞
 * Date: 2020/12/31
 * Time: 13:46
 */

namespace App\Task;

use App\Game\Conf\GameProgress;
use App\Game\Core\Log;
use App\Game\Core\Robot;
use App\Game\Core\Room;
use App\Game\Timer\GameTimer;
use App\Model\User;
use App\Game\Core\Packet;
use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use Psr\Container\ContainerInterface;
use Swoole\WebSocket\Server as WebSocketServer;

class CreateRoomTask
{
    /**
     * @var ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function createRoom($fd, $account, $is_join = false): void
    {
        $score = $this->checkScore($account);
        $redis = redis();
        $serv = server();
        $game_conf = config('game');
        $playing_room = $this->checkPlaying($account);
        if ($playing_room) {
            $msg = ['account' => $account, 'room_no' => $playing_room, 'status' => 1, 'info' => '有正在进行的游戏房间'];
            $data = Packet::packFormat('OK', 0, $msg);
            $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_ROOM_CREATE_RESP);
            $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);//向用户广播
            $room_data = getRoomData($playing_room);

            $timer = json_decode($room_data['timer'], true);
            $now = time();
            $gameTime = strtotime($timer['time']);
            if ($now - $gameTime > 20) {
                $msg = ['status' => '强制退出'];
                pushDataToUser($serv, $fd, $msg, SubCmd::FORCE_QUIT_ROOM_RESP);
                //清空房间
                clearRoomDataAll($playing_room);
                return;
            }
            return;
        } elseif (!$score) {
            $msg = ['account' => $account, 'room_no' => null, 'status' => 2, 'info' => '积分不足'];
            $data = Packet::packFormat('OK', 0, $msg);
            $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_ROOM_CREATE_RESP);
            $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);//向用户广播
            return;
        } else {
            // 创建房间号
            $room_no = Room::createRoomNo();
            // uid=>room_no映射
            $room_map_key = sprintf($game_conf['user_room'], $account);
            $redis->set($room_map_key, $room_no);

            // room_no=>[uid1,uid2]
            $room_wait_key = sprintf($game_conf['user_room_wait'], $room_no);
            $redis->set($room_wait_key, json_encode([$account], JSON_UNESCAPED_SLASHES));

            setGameProgress($room_no, GameProgress::GAME_JOIN);

            $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
            $chair_data[$account] = 1;
            $redis->set($room_chair_key, json_encode($chair_data, JSON_UNESCAPED_SLASHES));

            // 所有房间集合
            $redis->sAdd($game_conf['user_room_total'], $room_no);
            $userInfo = User::userInfo($account);
            $is_real = 1;
            if ($is_join) {
                $is_real = 0;
            }
            $msg = ['room_no' => $room_no, 'is_real' => $is_real, 'player' => $userInfo, 'status' => 0, 'info' =>
                '创建成功', 'chair_id' => 1];
            $data = Packet::packFormat('OK', 1, $msg);
            $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_ROOM_CREATE_RESP);
            $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);//向用户广播
            //快速开始途径调用的创建房间，才能添加机器人
            if ($is_join) {
                //设置游戏进度类型为单机
                setGameProgressType($room_no, 1);
                return;
            }
            //推入等待队列
            $playersData[] = $account;
            Room::createWaitRoom($room_no, $playersData);
        }
    }

    /**
     * * 检查用户的积分
     * @param $account
     * @return bool
     */
    public function checkScore($account)
    {
        $user_conf = config('user');
        $user_info = User::userInfo($account);
        if (($user_info['score']) > $user_conf['create_room_score']) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查有无正在游戏房间
     * @param $account
     * @return bool
     */
    public function checkPlaying($account)
    {
        $game_conf = config('game');
        $redis = redis();
        $user_map_key = sprintf($game_conf['user_room'], $account);
        if ($redis->exists($user_map_key)) {
            $room_no = $redis->get($user_map_key);
            $type = getGameProgressType($room_no);
            if ($type) {//单机
                clearRoomDataAll($room_no);
                return false;
            }
            $room_wait_key = sprintf($game_conf['user_room_wait'], $room_no);
            if ($redis->exists($room_wait_key)) {
                return $room_no;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 世界广播
     * @param $serv
     * @param $data
     */
    protected function worldBroadcast($serv, $self_fd)
    {
        $hallData = $this->hallData();
        $data = Packet::packFormat('OK', 1, $hallData);
        $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_HALL_RESP);
        foreach ($serv->connections as $fd) {
            if ($self_fd != $fd) {
                $client_info = $serv->getClientInfo($fd);
                $client[$fd] = $client_info;
                if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                    $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
                }
            }
        }
    }

    /**
     * 游戏大厅房间数据
     * @return array
     */
    protected function hallData()
    {
        $game_conf = config('game');
        $room_total_key = $game_conf['user_room_total'];
        $fake_room_data = $this->fakeHallData();
        if (redis()->exists($room_total_key)) {
            $rooms = redis()->sMembers($room_total_key);
            $hall_rooms = array();
            $hall_datas = array();
            $wait_room_conf = $game_conf['user_room_wait'];
            $room_data_conf = $game_conf['user_room_data'];
            foreach ($rooms as $val) {
                $wait_room_key = sprintf($wait_room_conf, $val);
                $room_data_key = sprintf($room_data_conf, $val);
                // 正在等待的房间
                if (redis()->exists($wait_room_key)) {
                    $hall_rooms[$val] = json_decode(redis()->get($wait_room_key), true);
                }
                // 正在游戏的房间
                if (redis()->exists($room_data_key)) {
                    $room_data = redis()->hGetAll($room_data_key);
                    if (!isset($room_data['is_game_over']) || ($room_data['is_game_over'] == 0)) {
                        if (!empty($room_data['uinfo'])) {
                            $wait_users = [];   // 正在等待房间里的用户account
                            $room_data_uinfo = json_decode($room_data['uinfo'], true);
                            dd('$room_data_uinfo', $room_data_uinfo);
                            if (gettype($room_data_uinfo) == 'string') {
                                $room_data_uinfo = json_decode($room_data_uinfo, true);
                            }
                            foreach ($room_data_uinfo as $ks => $vs) {
                                $wait_users[] = $ks;
                            }
                            $hall_rooms[$val] = $wait_users;
                        }
                    }
                }
            }
            if (!empty($hall_rooms)) {
                // 查询个房号用户信息
                $i = 0;
                foreach ($hall_rooms as $k => $v) {
                    if (!empty($v)) {
                        // 房间用户存在，查询用户信息
                        $curr_room_users = User::getUsers($v);
                        if ($curr_room_users['code'] == 0) {
                            $curr_room_data = $curr_room_users['data'];
                            foreach ($curr_room_data as $ks => $vs) {
                                $curr_room_data[$ks]['chair_id'] = findChairId($k, $vs['account']);
                            }
                            $hall_datas[$i]['room_no'] = $k;
                            $hall_datas[$i]['room_data'] = $curr_room_data;
                        }
                        $i++;
                    }
                }
                $total_room_data = array_merge($fake_room_data, $hall_datas);
                return $total_room_data;
            } else {
                return $fake_room_data;
            }
        } else {
            return $fake_room_data;
        }
    }

    /**
     * 返回玩家房间桌位号
     * @param $room_no
     * @param $account
     * @return mixed
     */
    protected function findChairId($room_no, $account)
    {
        $game_conf = config('game');
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $chair_data = json_decode(redis()->get($room_chair_key), true);
        return $chair_data[$account];
    }

    /**
     * 模拟大厅数据
     */
    protected function fakeHallData()
    {
        $game_conf = config('game');
        $fake_room_key = $game_conf['fake_room_hallFake'];
        $fake_expire = $game_conf['fake_expire'];
        if (redis()->exists($fake_room_key)) {
            $fake_room_data = json_decode(redis()->get($fake_room_key), true);
            return $fake_room_data;
        } else {
            $num = rand(10000, 99999);
            $data = User::getUserNum($num);
            $fake_room_data = [];
            $team_arr = array_chunk($data, 3);
            $room_no = 9989;
            foreach ($team_arr as $k => $v) {
                $team_data = [];
                if (!empty($v)) {
                    foreach ($v as $kk => $vv) {
                        $team_data[] = [
                            'account' => $vv['account'],
                            'score' => $vv['score'],
                            'avatar' => $vv['avatar'],
                            'chair_id' => (int)($kk + 1),
                        ];
                    }
                }
                $fake_room_data[] = ['room_data' => $team_data, 'room_no' => (int)($room_no + $k)];
            }
            // 缓存模拟房间数据
            redis()->set($fake_room_key, json_encode($fake_room_data, JSON_UNESCAPED_SLASHES));
            redis()->expire($fake_room_key, $fake_expire);
            return $fake_room_data;
        }
    }

    protected function filterNickname($account)
    {
        $regex = "/\/|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\+|\{|\}|\:|\<|\>|\?|\[|\]|\,|\.|\/|\;|\'|\`|\-|\=|\\\|\|[\x{1F600}-\x{1F64F}]|[\x{1F300}-\x{1F5FF}]|[\x{1F680}-\x{1F6FF}]|[\x{2600}-\x{26FF}]|[\x{2700}-\x{27BF}]|/";
        $str = preg_replace($regex, '', $account);
        return preg_replace('# #', '', $str);
    }
}